package com.lemon.exam.common.util;

import com.lemon.exam.common.entity.dto.CaptchaDTO;
import com.lemon.exam.common.exception.CustomException;
import com.lemon.exam.common.web.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 图片验证码工具类
 *
 * @author Lemon
 * @since 2025/4/1 21:33
 */
@Slf4j
public class CaptchaUtil {
    // 默认验证码长度
    private static final int DEFAULT_CODE_LENGTH = 4;
    // 默认图片宽度
    private static final int DEFAULT_WIDTH = 90;
    // 默认图片高度
    private static final int DEFAULT_HEIGHT = 40;
    // 默认干扰线数量
    private static final int DEFAULT_LINE_COUNT = 20;
    // 默认干扰点数量
    private static final int DEFAULT_POINT_COUNT = 50;

    /**
     * 生成默认验证码（纯白色背景）
     *
     * @return
     */
    public static Mono<CaptchaDTO> generate() {
        return generate(Color.WHITE);
    }

    /**
     * 生成验证码
     *
     * @param bgColor
     * @return
     */
    public static Mono<CaptchaDTO> generate(Color bgColor) {
        return generate(DEFAULT_CODE_LENGTH, DEFAULT_WIDTH, DEFAULT_HEIGHT, bgColor);
    }

    /**
     * 生成验证码
     *
     * @param codeLength 验证码长度
     * @param width      图片宽度
     * @param height     图片高度
     */
    public static Mono<CaptchaDTO> generate(int codeLength, int width, int height, Color bgColor) {
        return Mono.fromCallable(() -> {
            // 创建BufferedImage对象
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            // 获取Graphics2D
            Graphics2D g = image.createGraphics();
            // 启用混合模式以实现透明度
            g.setComposite(AlphaComposite.SrcOver);
            // 设置背景色
            g.setColor(bgColor);
            //g.setBackground(new Color(1.0f, 1.0f, 1.0f, 0.1f));
            g.fillRect(0, 0, width, height);
            // 设置字体
            g.setFont(new Font("Arial", Font.BOLD, (int) (height * 0.8)));
            // 生成随机数
            Random random = ThreadLocalRandom.current();
            // 生成验证码
            String code = RandomUtil.all(codeLength);
            for (int i = 0; i < codeLength; i++) {
                char c = code.charAt(i);
                // 设置字符颜色
                g.setColor(new Color(random.nextInt(150), random.nextInt(150), random.nextInt(150)));
                // 绘制字符
                if (i == 0) {
                    g.drawString(String.valueOf(c), 0, (int) (height * 0.8));
                } else {
                    g.drawString(String.valueOf(c), (int) (width * 0.01) + i * (width / codeLength), (int) (height * 0.8));
                }

            }
            // 添加干扰线
            for (int i = 0; i < DEFAULT_LINE_COUNT; i++) {
                g.setColor(getRandomColor(random, 150, 250));
                g.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));
            }
            // 添加干扰点
            for (int i = 0; i < DEFAULT_POINT_COUNT; i++) {
                g.setColor(getRandomColor(random, 150, 250));
                g.drawOval(random.nextInt(width), random.nextInt(height), 1, 1);
            }
            // 释放资源
            g.dispose();

            return new CaptchaDTO(UUID.randomUUID().toString(), code, image);
        });
    }

    /**
     * 生成随机颜色
     */
    private static Color getRandomColor(Random random, int fc, int bc) {
        if (fc > 255) fc = 255;
        if (bc > 255) bc = 255;
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

    /**
     * 返回包含验证码图片的Mono
     */
    public static Mono<ServerResponse> createResponse(CaptchaDTO captcha, String type) {
        return ServerResponse.ok()
                .contentType(MediaType.IMAGE_JPEG)
                .header("uuid", captcha.uuid())
                .bodyValue(captcha.getImageBytes(type));
    }

    /**
     * 返回包含验证码图片的Base64编码的Mono
     *
     * @param captcha
     * @return
     */
    public static Mono<ServerResponse> createBase64Response(CaptchaDTO captcha, String type) {
        return ServerResponse.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .header("uuid", captcha.uuid())
                .bodyValue(Result.ok(captcha.getBase64Image(type)));
    }
}
